home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / aztecnos.arc / IP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-19  |  11.4 KB  |  462 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  */
  5. #define    TLB    30 * (1000/MSPTICK)    /* Reassembly limit time */
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "timer.h"
  9. #include "internet.h"
  10. #include "iface.h"
  11. #include "ip.h"
  12. #include "icmp.h"
  13.  
  14. extern struct raw_ip *Raw_ip;
  15. extern struct mbuf *Hopper;
  16. extern struct iface Loopback;
  17.  
  18. static struct mbuf *fraghandle();
  19. static void ip_timeout(),free_reasm(),freefrag();
  20. static struct reasm *lookup_reasm(),*creat_reasm();
  21. static struct frag *newfrag();
  22.  
  23.  
  24. char Ip_ttl = MAXTTL;    /* Default time-to-live for IP datagrams */
  25. struct reasm *Reasmq;
  26. struct raw_ip *Raw_ip;
  27.  
  28. #define    INSERT    0
  29. #define    APPEND    1
  30. #define    PREPEND    2
  31.  
  32. /* Send an IP datagram. Modeled after the example interface on p 32 of
  33.  * RFC 791
  34.  */
  35. int
  36. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  37. int32 source;            /* source address */
  38. int32 dest;            /* Destination address */
  39. char protocol;            /* Protocol */
  40. char tos;            /* Type of service */
  41. char ttl;            /* Time-to-live */
  42. struct mbuf *bp;        /* Data portion of datagram */
  43. int16 length;            /* Optional length of data portion */
  44. int16 id;            /* Optional identification */
  45. char df;            /* Don't-fragment flag */
  46. {
  47.     struct mbuf *tbp;
  48.     struct ip ip;        /* Pointer to IP header */
  49.     static int16 id_cntr;    /* Datagram serial number */
  50.     struct phdr *phdr;
  51.  
  52.     if(length == 0 && bp != NULLBUF)
  53.         length = len_mbuf(bp);
  54.     if(id == 0)
  55.         id = id_cntr++;        
  56.     if(ttl == 0)
  57.         ttl = Ip_ttl;
  58.  
  59.     /* Fill in IP header */
  60.     ip.tos = tos;
  61.     ip.length = IPLEN + length;
  62.     ip.id = id;
  63.     ip.offset = 0;
  64.     ip.flags.mf = 0;
  65.     ip.flags.df = df;
  66.     ip.ttl = ttl;
  67.     ip.protocol = protocol;
  68.     ip.source = source;
  69.     ip.dest = dest;
  70.     ip.optlen = 0;
  71.     if((tbp = htonip(&ip,bp)) == NULLBUF){
  72.         free_p(bp);
  73.         return -1;
  74.     }
  75.     if((bp = pushdown(tbp,sizeof(struct phdr))) == NULLBUF){
  76.         free_p(tbp);
  77.         return -1;
  78.     }
  79.     phdr = (struct phdr *)bp->data;
  80.     if(ip.dest == Ip_addr)
  81.         phdr->iface = &Loopback;
  82.     else
  83.         phdr->iface = NULLIF;
  84.  
  85.     phdr->type = TYPE_IP;    
  86.     enqueue(&Hopper,bp);
  87.     return 0;
  88. }
  89.  
  90. /* Reassemble incoming IP fragments and dispatch completed datagrams
  91.  * to the proper transport module
  92.  */
  93. void
  94. ip_recv(ip,bp,rxbroadcast)
  95. struct ip *ip;        /* Extracted IP header */
  96. struct mbuf *bp;    /* Data portion */
  97. char rxbroadcast;    /* True if received on subnet broadcast address */
  98. {
  99.     void (*recv)();    /* Function to call with completed datagram */
  100.     register struct raw_ip *rp;
  101.     struct mbuf *bp1,*tbp;
  102.     int rxcnt = 0;
  103.  
  104.     /* If we have a complete packet, call the next layer
  105.      * to handle the result. Note that fraghandle passes back
  106.      * a length field that does NOT include the IP header
  107.      */
  108.     if((bp = fraghandle(ip,bp)) == NULLBUF)
  109.         return;        /* Not done yet */
  110.  
  111.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next){
  112.         if(rp->protocol != ip->protocol)
  113.             continue;
  114.         rxcnt++;
  115.         /* Duplicate the data portion, and put the header back on */
  116.         dup_p(&bp1,bp,0,len_mbuf(bp));
  117.         if(bp1 != NULLBUF && (tbp = htonip(ip,bp1)) != NULLBUF){
  118.             enqueue(&rp->rcvq,tbp);
  119.         } else {
  120.             free_p(bp1);
  121.         }
  122.     }
  123.     /* Check for protocols we can't handle */
  124.     switch(uchar(ip->protocol)){
  125.     case TCP_PTCL:
  126.         recv = tcp_input;
  127.         break;
  128.     case UDP_PTCL:
  129.         recv = udp_input;
  130.         break;
  131.     case ICMP_PTCL:
  132.         recv = icmp_input;
  133.         break;
  134.     default:
  135.         recv = NULLVFP;
  136.         break;
  137.     }
  138.     if(recv != NULLVFP){
  139.         /* Pass the completed packet upstairs */
  140.         (*recv)(bp,ip->protocol,ip->source,ip->dest,ip->tos,
  141.             ip->length - (IPLEN + ip->optlen),rxbroadcast);
  142.     } else {
  143.         if(rxcnt == 0){
  144.             /* Send an ICMP Protocol Unknown response... */
  145.             Ip_stats.badproto++;
  146.             /* ...unless it's a broadcast */
  147.             if(!rxbroadcast){
  148.                 icmp_output(ip,bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  149.             }
  150.         }
  151.         free_p(bp);
  152.     }
  153. }
  154. /* Process IP datagram fragments
  155.  * If datagram is complete, return it with ip->length containing the data
  156.  * length (MINUS header); otherwise return NULLBUF
  157.  */
  158. static
  159. struct mbuf *
  160. fraghandle(ip,bp)
  161. struct ip *ip;        /* IP header, host byte order */
  162. struct mbuf *bp;    /* The fragment itself */
  163. {
  164.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  165.     struct frag *lastfrag,*nextfrag,*tfp;
  166.     struct mbuf *tbp;
  167.     int16 i;
  168.     int16 last;        /* Index of first byte beyond fragment */
  169.  
  170.     last = ip->offset + ip->length - (IPLEN + ip->optlen);
  171.  
  172.     rp = lookup_reasm(ip);
  173.     if(ip->offset == 0 && !ip->flags.mf){
  174.         /* Complete datagram received. Discard any earlier fragments */
  175.         if(rp != NULLREASM)
  176.             free_reasm(rp);
  177.  
  178.         return bp;
  179.     }
  180.     if(rp == NULLREASM){
  181.         /* First fragment; create new reassembly descriptor */
  182.         if((rp = creat_reasm(ip)) == NULLREASM){
  183.             /* No space for descriptor, drop fragment */
  184.             free_p(bp);
  185.             return NULLBUF;
  186.         }
  187.     }
  188.     /* Keep restarting timer as long as we keep getting fragments */
  189.     stop_timer(&rp->timer);
  190.     start_timer(&rp->timer);
  191.  
  192.     /* If this is the last fragment, we now know how long the
  193.      * entire datagram is; record it
  194.      */
  195.     if(!ip->flags.mf)
  196.         rp->length = last;
  197.  
  198.     /* Set nextfrag to the first fragment which begins after us,
  199.      * and lastfrag to the last fragment which begins before us
  200.      */
  201.     lastfrag = NULLFRAG;
  202.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  203.         if(nextfrag->offset > ip->offset)
  204.             break;
  205.         lastfrag = nextfrag;
  206.     }
  207.     /* Check for overlap with preceeding fragment */
  208.     if(lastfrag != NULLFRAG  && ip->offset < lastfrag->last){
  209.         /* Strip overlap from new fragment */
  210.         i = lastfrag->last - ip->offset;
  211.         pullup(&bp,NULLCHAR,i);
  212.         if(bp == NULLBUF)
  213.             return NULLBUF;    /* Nothing left */
  214.         ip->offset += i;
  215.     }
  216.     /* Look for overlap with succeeding segments */
  217.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  218.         tfp = nextfrag->next;    /* save in case we delete fp */
  219.  
  220.         if(nextfrag->offset >= last)
  221.             break;    /* Past our end */
  222.         /* Trim the front of this entry; if nothing is
  223.          * left, remove it.
  224.          */
  225.         i = last - nextfrag->offset;
  226.         pullup(&nextfrag->buf,NULLCHAR,i);
  227.         if(nextfrag->buf == NULLBUF){
  228.             /* superseded; delete from list */
  229.             if(nextfrag->prev != NULLFRAG)
  230.                 nextfrag->prev->next = nextfrag->next;
  231.             else
  232.                 rp->fraglist = nextfrag->next;
  233.             if(tfp->next != NULLFRAG)
  234.                 nextfrag->next->prev = nextfrag->prev;
  235.             freefrag(nextfrag);
  236.         } else
  237.             nextfrag->offset = last;
  238.     }
  239.     /* Lastfrag now points, as before, to the fragment before us;
  240.      * nextfrag points at the next fragment. Check to see if we can
  241.      * join to either or both fragments.
  242.      */
  243.     i = INSERT;
  244.     if(lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  245.         i |= APPEND;
  246.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  247.         i |= PREPEND;
  248.     switch(i){
  249.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  250.         tfp = newfrag(ip->offset,last,bp);
  251.         tfp->prev = lastfrag;
  252.         tfp->next = nextfrag;
  253.         if(lastfrag != NULLFRAG)
  254.             lastfrag->next = tfp;    /* Middle of list */
  255.         else
  256.             rp->fraglist = tfp;    /* First on list */
  257.         if(nextfrag != NULLFRAG)
  258.             nextfrag->prev = tfp;
  259.         break;
  260.     case APPEND:    /* Append to lastfrag */
  261.         append(&lastfrag->buf,bp);
  262.         lastfrag->last = last;    /* Extend forward */
  263.         break;
  264.     case PREPEND:    /* Prepend to nextfrag */
  265.         tbp = nextfrag->buf;
  266.         nextfrag->buf = bp;
  267.         append(&nextfrag->buf,tbp);
  268.         nextfrag->offset = ip->offset;    /* Extend backward */
  269.         break;
  270.     case (APPEND|PREPEND):
  271.         /* Consolidate by appending this fragment and nextfrag
  272.          * to lastfrag and removing the nextfrag descriptor
  273.          */
  274.         append(&lastfrag->buf,bp);
  275.         append(&lastfrag->buf,nextfrag->buf);
  276.         nextfrag->buf = NULLBUF;
  277.         lastfrag->last = nextfrag->last;
  278.  
  279.         /* Finally unlink and delete the now unneeded nextfrag */
  280.         lastfrag->next = nextfrag->next;
  281.         if(nextfrag->next != NULLFRAG)
  282.             nextfrag->next->prev = lastfrag;
  283.         freefrag(nextfrag);
  284.         break;
  285.     }
  286.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  287.         && rp->length != 0){
  288.         /* We've gotten a complete datagram, so extract it from the
  289.          * reassembly buffer and pass it on.
  290.          */
  291.         bp = rp->fraglist->buf;
  292.         rp->fraglist->buf = NULLBUF;
  293.         /* Tell IP the entire length */
  294.         ip->length = rp->length + (IPLEN + ip->optlen);
  295.         free_reasm(rp);
  296.         return bp;
  297.     } else
  298.         return NULLBUF;
  299. }
  300. /* Arrange for receipt of raw IP datagrams */
  301. struct raw_ip *
  302. raw_ip(protocol)
  303. char protocol;
  304. {
  305.     register struct raw_ip *rp;
  306.  
  307.     rp = (struct raw_ip *)calloc(1,sizeof(struct raw_ip));
  308.     rp->protocol = protocol;
  309.     rp->next = Raw_ip;
  310.     if(rp->next != NULLRIP)
  311.         rp->next->prev = rp;
  312.     Raw_ip = rp;
  313.     return rp;
  314. }
  315. /* Free a raw IP descriptor */
  316. void
  317. del_ip(rpp)
  318. struct raw_ip *rpp;
  319. {
  320.     register struct raw_ip *rp;
  321.  
  322.     /* Do sanity check on arg */
  323.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next)
  324.         if(rp == rpp)
  325.             break;
  326.     if(rp == NULLRIP)
  327.         return;    /* Doesn't exist */
  328.  
  329.     /* Unlink */
  330.     if(rp->prev != NULLRIP)
  331.         rp->prev->next = rp->next;
  332.     else
  333.         Raw_ip = rp->next;
  334.     if(rp->next != NULLRIP)
  335.         rp->next->prev = rp->prev;
  336.     /* Free resources */
  337.     free_q(&rp->rcvq);
  338.     free((char *)rp);
  339. }
  340.  
  341. static struct reasm *
  342. lookup_reasm(ip)
  343. struct ip *ip;
  344. {
  345.     register struct reasm *rp;
  346.  
  347.     for(rp = Reasmq;rp != NULLREASM;rp = rp->next){
  348.         if(ip->source == rp->source && ip->dest == rp->dest
  349.          && ip->protocol == rp->protocol && ip->id == rp->id)
  350.             return rp;
  351.     }
  352.     return NULLREASM;
  353. }
  354. #ifdef    FOO
  355. static
  356. int16
  357. hash_reasm(source,dest,protocol,id)
  358. int32 source;
  359. int32 dest,
  360. char protocol;
  361. int16 id;
  362. {
  363.     register unsigned int hval;
  364.  
  365.     hval = loword(source);
  366.     hval ^= hiword(source);
  367.     hval ^= loword(dest);
  368.     hval ^= hiword(dest);
  369.     hval ^= uchar(protocol);
  370.     hval ^= id;
  371.     return hval % RHASH;
  372. }
  373. #endif
  374. /* Create a reassembly descriptor,
  375.  * put at head of reassembly list
  376.  */
  377. static struct reasm *
  378. creat_reasm(ip)
  379. register struct ip *ip;
  380. {
  381.     register struct reasm *rp;
  382.  
  383.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  384.         return rp;    /* No space for descriptor */
  385.     rp->source = ip->source;
  386.     rp->dest = ip->dest;
  387.     rp->id = ip->id;
  388.     rp->protocol = ip->protocol;
  389.     rp->timer.start = TLB;
  390.     rp->timer.func = ip_timeout;
  391.     rp->timer.arg = (char *)rp;
  392.  
  393.     rp->next = Reasmq;
  394.     if(rp->next != NULLREASM)
  395.         rp->next->prev = rp;
  396.     Reasmq = rp;
  397.     return rp;
  398. }
  399.  
  400. /* Free all resources associated with a reassembly descriptor */
  401. static void
  402. free_reasm(rp)
  403. register struct reasm *rp;
  404. {
  405.     register struct frag *fp;
  406.  
  407.     stop_timer(&rp->timer);
  408.     /* Remove from list of reassembly descriptors */
  409.     if(rp->prev != NULLREASM)
  410.         rp->prev->next = rp->next;
  411.     else
  412.         Reasmq = rp->next;
  413.     if(rp->next != NULLREASM)
  414.         rp->next->prev = rp->prev;
  415.     /* Free any fragments on list, starting at beginning */
  416.     while((fp = rp->fraglist) != NULLFRAG){
  417.         rp->fraglist = fp->next;
  418.         free_p(fp->buf);
  419.         free((char *)fp);
  420.     }
  421.     free((char *)rp);
  422. }
  423.  
  424. /* Handle reassembly timeouts by deleting all reassembly resources */
  425. static void
  426. ip_timeout(arg)
  427. int *arg;
  428. {
  429.     register struct reasm *rp;
  430.  
  431.     rp = (struct reasm *)arg;
  432.     free_reasm(rp);
  433. }
  434. /* Create a fragment */
  435. static
  436. struct frag *
  437. newfrag(offset,last,bp)
  438. int16 offset,last;
  439. struct mbuf *bp;
  440. {
  441.     struct frag *fp;
  442.  
  443.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  444.         /* Drop fragment */
  445.         free_p(bp);
  446.         return NULLFRAG;
  447.     }
  448.     fp->buf = bp;
  449.     fp->offset = offset;
  450.     fp->last = last;
  451.     return fp;
  452. }
  453. /* Delete a fragment, return next one on queue */
  454. static
  455. void
  456. freefrag(fp)
  457. struct frag *fp;
  458. {
  459.     free_p(fp->buf);
  460.     free((char *)fp);
  461. }
  462.